package com.clinic.accessor.db;

import java.sql.SQLException;
import java.util.Collections;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.clinic.entity.param.Index;

public abstract class AbstractDbAccessor<T> extends HibernateDaoSupport {

	protected static final String PRIMARY_KEY_PERFIX = "id.";
	private static final Logger LOGGER = Logger.getLogger(AbstractDbAccessor.class);
	protected DetachedCriteria criteria;
	
	@Autowired
	public void init(SessionFactory sessionFactory) {
		setSessionFactory(sessionFactory);
	}
	
	@SuppressWarnings("unchecked")
	public T insertOrUpdate(T entity) {
		if (entity != null) {
			try {
				return (T) getHibernateTemplate().merge(entity);
			} catch (DataAccessException e) {
				LOGGER.error(e.getMessage(), e);
			}
	    }
		return null;
    }
	
	public void delete(T entity) {
		if (entity != null) {
			getHibernateTemplate().delete(entity);
	    }
    }
	
	public int getCount(final DetachedCriteria criteria) {
		criteria.setProjection(Projections.rowCount());
		return ((Long) uniqueObject(criteria)).intValue();
	}
	
	@SuppressWarnings("unchecked")
	protected List<T> listGeneric(DetachedCriteria criteria, Index index) {
   		List<T> result = (List<T>) doExecute(criteria, index);
   		return result;
    }
	
	protected T uniqueGeneric(DetachedCriteria criteria) {
		T result = null;
		List<T> list = listGeneric(criteria, new Index(1));
		if (list != null && list.size() > 0) {
			result = list.get(0);
		}
		return result;
	}
	
	@SuppressWarnings("unchecked")
	protected List<Long> listLong(DetachedCriteria criteria, Index index) {
		List<Long> resultList = (List<Long>)listGeneric(criteria, index);
		return resultList;
	}
	
	protected int count(DetachedCriteria criteria) {
		Integer count = getCount(criteria);
		if (count == null) {
			count = 0;
		}
		return count;
	}
	
	private Object uniqueObject(DetachedCriteria criteria) {
		Object result = null;
		@SuppressWarnings("unchecked")
		List<Object> list = (List<Object>) doExecute(criteria, new Index(1));
		if (list != null && list.size() > 0) {
			result = list.get(0);
		}
		return result;
	}
	
	private List<?> doExecute(final DetachedCriteria detachedCriteria, final Index index) {
		if (index.getMaxItems() == 0) {
			return Collections.emptyList();
		} else {
			List<?> result = (List<?>) getHibernateTemplate().execute(new HibernateCallback() {
				@Override
				public Object doInHibernate(Session session) throws HibernateException, SQLException {
					Criteria criteria = (detachedCriteria).getExecutableCriteria(session);
					criteria.setFirstResult(index.getStartIndex());
					criteria.setMaxResults(index.getMaxItems());
					List<?> result = criteria.list();
					return result;
				}
	    	});
			return result;
		}
	}	
	
	/*public void insertOrUpdateAll(List<T> entities) {
		if (entities != null && ! entities.isEmpty()) {
			for(T entity : entities){
				insertOrUpdate(entity);
			}
		}
	}*/
	
	
	/*public void deleteAll(List<T> entities) {
		if (entities != null) {
			getHibernateTemplate().deleteAll(entities);
		}
	}*/
	
	
	/*@SuppressWarnings("unchecked")
	protected List<Object> listObject(DetachedCriteria criteria, Index index) {
		List<Object> result = (List<Object>) excuteObjectList(criteria, index);
		return result;
	}*/
	
	/*@SuppressWarnings("unchecked")
	private T mergeGeneric(T entity) {
		try {
			return (T) getHibernateTemplate().merge(entity);
		} catch (DataAccessException e) {
			LOGGER.error(e.getMessage(), e);
		}
		return null;
	}*/
	
	/*private void mergeAllGenerics(List<T> entities) {
		for (T entity : entities) {
			mergeGeneric(entity);
		}
//		try {
//			getHibernateTemplate().saveOrUpdateAll(entities); // TODO different id needs
//		} catch (Exception e) {
//			LOGGER.error(e.getMessage(), e);
//		}
	}*/
	
}
